package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 资源列表
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheConstant.RESOURCE_LIST,key = "#resourceDto.hashCode()")
    public List<ResourceVo> list(ResourceDto resourceDto) {
//        Copy
//        Resource resource = new Resource();
//        BeanUtil.copyProperties(resourceDto,resource);
        Resource bean = BeanUtil.toBean(resourceDto, Resource.class);
        List<Resource> list = resourceMapper.list(bean);
        return BeanUtil.copyToList(list, ResourceVo.class);
    }

    /**
     * 资源树形
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheConstant.RESOURCE_TREE,key = "#resourceDto.hashCode()")
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        //1.创建返回数据的对象
        TreeVo treeVo = new TreeVo();
        //2.创建根节点 并构建目录关系
        TreeItemVo root = new TreeItemVo();
        root.setId(SuperConstant.ROOT_PARENT_ID);
        root.setLabel("智慧养老院");

        List<TreeItemVo> list = new ArrayList<>();
        list.add(root);
        treeVo.setItems(list);
        //3.通过条件查询所有的菜单节点(把Dto放到pojo中)
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        resource.setParentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID));
        resource.setResourceType(SuperConstant.MENU);
        resource.setDataState(SuperConstant.DATA_STATE_0);
        List<Resource> listResource = resourceMapper.list(resource);

        //4.通过节点查找所有的一级目录 并构建关系
        List<Resource> firstTree = listResource.stream().filter(r -> {
            if (r.getParentResourceNo().equals(root.getId())) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());

        List<TreeItemVo> firstTreeList = firstTree.stream().map(r -> {
            TreeItemVo vo = new TreeItemVo();
            vo.setId(r.getResourceNo());
            vo.setLabel(r.getResourceName());
            return vo;
        }).collect(Collectors.toList());
        //构建关系
        root.setChildren(firstTreeList);

        //5.遍历每一个一级目录 然后找对应的一级目录下的二级目录 并构建关系
        root.getChildren().stream().map(first ->{
            List<Resource> secondTree = listResource.stream().filter(r -> {
                if (r.getParentResourceNo().equals(first.getId())) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());

            List<TreeItemVo> secondTreeList = secondTree.stream().map(r -> {
                TreeItemVo vo = new TreeItemVo();
                vo.setId(r.getResourceNo());
                vo.setLabel(r.getResourceName());
                return vo;
            }).collect(Collectors.toList());
            first.setChildren(secondTreeList);
            return first;
        }).collect(Collectors.toList());

        //6.遍历每一个二级目录 然后找找对应的二级目录下的三级目录 并构建关系
        root.getChildren().stream().map(first ->{
            first.getChildren().stream().map(second ->{
                List<Resource> thirdTree = listResource.stream().filter(r -> {
                    if (r.getParentResourceNo().equals(second.getId())) {
                        return true;
                    } else {
                        return false;
                    }
                }).collect(Collectors.toList());

                List<TreeItemVo> thirdThreeList = thirdTree.stream().map(r -> {
                    TreeItemVo vo = new TreeItemVo();
                    vo.setId(r.getResourceNo());
                    vo.setLabel(r.getResourceName());
                    return vo;
                }).collect(Collectors.toList());
                second.setChildren(thirdThreeList);
                return second;
            }).collect(Collectors.toList());
            return first;
        }).collect(Collectors.toList());
            //7.返回结果
            return treeVo;
        }

    /**
     * 添加资源
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true)
    })
    public void createResource(ResourceDto resourceDto) {
        //1.把dto转换为pojo
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //2.根据父资源的no查询父菜单 然后把当前菜单状态设置为父菜单的状态
        Resource r = new Resource();
        r.setParentResourceNo(resource.getParentResourceNo());
        List<Resource> list = resourceMapper.selectByParentNo(r.getParentResourceNo());
        if(null == list || list.size() == 0){
            throw new BaseException(BasicEnum.PANRENT_MENU_NOT_EXIST);
        }
        resource.setDataState(list.get(0).getDataState());

        //3.补齐常规字段
        resource.setCreateTime(LocalDateTime.now());
        resource.setUpdateTime(LocalDateTime.now());
        resource.setCreateBy(1662379840570994691L);
        resource.setLabel(resource.getRequestPath().replaceAll("/",":"));
        resource.setRemark(resource.getResourceName());

        //4.根据父资源的编码生成子资源的编码
        resource.setResourceNo(createResourceNo(resource.getParentResourceNo(),resource.getResourceType()));

        //5.新增菜单
        resourceMapper.insert(resource);
    }

    /**
     * 根据父资源的编码生成子资源的编码
     * @param
     * @return
     */
    private String createResourceNo(String parentResourceNo,String resourceType) {
        if(null != resourceType && resourceType.equals(SuperConstant.MENU))
        {
            if(NoProcessing.processString(parentResourceNo).length() > 12){
                throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
            }
        }
        //通过父菜单的no查询所有子菜单 如果没有子菜单 则直接追加001 如果有子菜单 则找到最大的那个no 然后再+1
        Resource resource = new Resource();
        resource.setParentResourceNo(parentResourceNo);
        List<Resource> subMenu = resourceMapper.list(resource);
        if(null == subMenu || subMenu.size() == 0){
            //如果没有子菜单追加001
            return NoProcessing.createNo(parentResourceNo,false);
        }else{
            //如果有子菜单则找到最大的那个NO 然后+1
            Long maxNo = subMenu.stream().map(r -> Long.parseLong(r.getResourceNo())).max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(maxNo + "",true);
        }
    }

    /**
     * 动态菜单
     * @return
     */
    @Override
    public List<MenuVo> menus() {
        //1.根据ThreadLocal查询当前登录的用户
        Long userId = UserThreadLocal.get();

        //2.通过用户id查询用户的所有的菜单
        List<MenuVo> menuVoList = resourceMapper.selectMenuByUserId(userId);

        //3.根据菜单的父no进行分组统计
        Map<String, List<MenuVo>> parentMap = menuVoList.stream().collect(Collectors.groupingBy(MenuVo::getParentResourceNo));

        //4.遍历每一个菜单 用自己的resourceno到统计结果中查询数据 如果有子菜单 则设置关系
        menuVoList.forEach(menuVo -> {
            //构建redis 和meto 补齐字段
            menuVo.setRedirect("/" + menuVo.getName());
            MenuMetaVo menuMetaVo = new MenuMetaVo();
            menuMetaVo.setTitle(menuVo.getName());
            menuVo.setMeta(menuMetaVo);

            List<MenuVo> subList = parentMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(subList)){
                menuVo.setChildren(subList);
            }
        });
        return parentMap.get(SuperConstant.ROOT_PARENT_ID);
    }
}